home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 August: Tool Chest / Apple_Developer_Group_August_1996_Tool_Chest.iso / Sample Code / Snippets / Printing / PDlog Expand (TN PR09) / PDlog Expand.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-13  |  13.2 KB  |  480 lines  |  [TEXT/KAHL]

  1. /* PDlog Expand.c    Derived    from TN #95.
  2.  
  3. Dave Hersey, Apple Developer Technical Support.
  4.  
  5.     10/9/91…    v1.0
  6.     2/25/92…    v1.0.1 --> fixed lack of print handle tossing and added something to print.    <dmh>
  7.     9/29/93…    v1.0.2 --> fixed bug in Append_DITL (also in TN #95) which appends 2 extra bytes. <dmh>
  8.     6/20/95…    v1.0.3 --> updated for Universal Headers and MWC-PPC    <njvt>
  9.     11/16/95    v1.0.4 --> updated to use CallPItemProc() and PItemUPP. Make it fully ANSI.
  10.     6/10/96        v1.1   --> Use the OS's AppendDITL if it's there. Add balloon help.
  11.  
  12.     Explicitly include needed headers, so back-port to MPW is easier.    <davep>
  13.  
  14.     NOTE: Apple reserves the top half of the screen (where the current DITL
  15.     items are located). Applications may use the bottom half of the screen to
  16.     add items, but should not change any items in the top half of the screen.
  17.     An application should expand the print dialogs only as much as is
  18.     absolutely necessary.
  19.  
  20.     A global search and replace of 'Job' with 'Stl' will produce code that
  21.     modifies the style dialog.
  22.     
  23.  
  24. */
  25.  
  26. #include <Printing.h>
  27. #include <Dialogs.h>
  28. #include <Gestalt.h>
  29. #include <MixedMode.h>
  30. #include <SegLoad.h>
  31. #include <Resources.h>
  32. #include <ToolUtils.h>
  33. #include <Fonts.h>
  34.  
  35. static TPPrDlg PrtJobDialog;    /* pointer to job dialog */
  36.  
  37. /* 
  38.  
  39. This points to the following structure:
  40.  
  41. struct TPrDlg {
  42.     DialogRecord                    Dlg;                        // The Dialog window
  43.     ModalFilterUPP                    pFltrProc;                    // The Filter Proc.
  44.     PItemUPP                        pItemProc;                    // The Item evaluating proc.
  45.     THPrint                            hPrintUsr;                    // The user's print record.
  46.     Boolean                            fDoIt;
  47.     Boolean                            fDone;
  48.     long                            lUser1;                        // Four longs for apps to hang global data.
  49.     long                            lUser2;                        // Plus more stuff needed by the particular
  50.     long                            lUser3;                        // printing dialog.
  51.     long                            lUser4;
  52. };
  53. typedef struct TPrDlg TPrDlg;
  54. typedef TPrDlg *TPPrDlg;
  55. typedef TPPrDlg TPPrDlgRef;
  56.  
  57. */
  58.  
  59. /* Declare ‘pascal’ functions and procedures */
  60.  
  61. extern short    Append_DITL(TPPrDlg, short);        /* Our AppendDITL function.            */
  62. extern pascal    TPPrDlg MyJobDlgInit(THPrint);        /* Our extention to PrJobInit.        */
  63. extern pascal    void MyJobItems(TPPrDlg, short);    /* Our modal item handler.            */
  64. extern OSErr    Print(void);
  65.  
  66. #define MyDITL 256    /* resource ID of my DITL to be spliced onto job dialog */
  67.  
  68. THPrint hPrintRec;    /* handle to print record */
  69. long prFirstItem;    /* save our first item here */
  70. PItemUPP prPItemProc;    /* we need to store the old itemProc here */
  71.  
  72. /*-----------------------------------------------------------------------*/
  73.     WindowPtr    MyWindow;
  74.     OSErr    err;
  75.     Str255    myStr;
  76.  
  77. #if PRAGMA_ALIGN_SUPPORTED
  78. #pragma options align=mac68k
  79. #endif
  80.  
  81. typedef struct dialog_item_struct {
  82.     Handle    handle;    /* handle or procedure pointer for this item */
  83.     Rect    bounds;    /* display rectangle for this item */
  84.     char    type;    /* item type - 1 */
  85.     char    data[1];    /* length byte of data */
  86. } DialogItem, *DialogItemPtr, **DialogItemHandle;
  87.  
  88. typedef struct append_item_list_struct {
  89.     short    max_index; /* number of items - 1 */
  90.     DialogItem    items[1]; /* first item in the array */
  91. } ItemList, *ItemListPtr, **ItemListHandle;
  92.  
  93. typedef union signed_byte_union {
  94.     short    integer;
  95.     char    bytes[2];
  96. } ByteAccess;
  97.  
  98.  
  99. static Boolean append_exits(void);
  100. static Boolean append_exits(void)
  101. {
  102.     long    response;
  103.  
  104.     if (Gestalt(gestaltDITLExtAttr,&response) == noErr) {
  105.         return !!(response & (1 << gestaltDITLExtPresent));
  106.     } else {
  107.         return false;    /* simple-minded, but hey, so am I. -DaveP */
  108.     }
  109. }
  110.  
  111.  
  112. /*    This routine appends all of the items of a specified DITL    */
  113. /*    onto the end of a specified DLOG — We don’t even need to know the format    */
  114. /*    of the DLOG    */
  115.  
  116. /*    this will be done in 3 steps:    */
  117. /*    1. append the items of the specified DITL onto the existing DLOG    */
  118. /*    2. expand the original dialog window as required    */
  119. /*    3. return the adjusted number of the first new user item    */
  120.  
  121. short Append_DITL(TPPrDlg dialog, short item_list_ID)
  122. {
  123.     ItemListHandle     append_item_list;    /* handle to DITL being appended */
  124.     ItemListHandle    dlg_item_list;    /* handle to DLOG's item list */
  125.     short            first_item;
  126.  
  127.     dlg_item_list = (ItemListHandle)((DialogPeek)dialog)->items;
  128.     first_item = (**dlg_item_list).max_index + 2;
  129.  
  130.     append_item_list = (ItemListHandle)GetResource('DITL', item_list_ID);
  131.     if ( append_item_list == NULL ) {
  132.         DebugStr("\pError loading DITL resource");
  133.         return first_item;
  134.     }
  135.  
  136.     if (append_exits()) {
  137.         AppendDITL((DialogPtr)dialog, (Handle) append_item_list, appendDITLBottom);
  138.         return first_item;
  139.     } else {
  140.         Point        offset;
  141.         Rect        max_rect;
  142.         DialogItemPtr     item;    /* pointer to item being appended */
  143.         short        new_items, data_size, i;
  144.         ByteAccess    usb;
  145.         OSErr        err;
  146.  
  147.     /*
  148.         Using the original DLOG
  149.      
  150.         1. Remember the original window Size.
  151.         2. Set the offset Point to be the bottom of the original window.
  152.         3. Subtract 5 pixels from bottom and right, to be added
  153.         back later after we have possibly expanded window.
  154.         4. Get working Handle to original item list.
  155.         5. Calculate our first item number to be returned to caller.
  156.         6. Get locked Handle to DITL to be appended.
  157.         7. Calculate count of new items.
  158.     */
  159.      
  160.         if (dialog == NULL) ExitToShell();
  161.      
  162.         max_rect = ((DialogPeek)dialog)->window.port.portRect;
  163.         offset.v = max_rect.bottom;
  164.         offset.h = 0;
  165.         max_rect.bottom -= 5;
  166.         max_rect.right -= 5;
  167.      
  168.     
  169.         HLock((Handle)append_item_list);
  170.         new_items = (**append_item_list).max_index + 1;
  171.      
  172.     /*
  173.         For each item,
  174.         1. Offset the rectangle to follow the original window.
  175.         2. Make the original window larger if necessary.
  176.         3. fill in item handle according to type.
  177.     */
  178.      
  179.         item = (**append_item_list).items;
  180.         for ( i = 0; i < new_items; i++ )
  181.         {
  182.             OffsetRect(&item->bounds, offset.h, offset.v);
  183.             UnionRect(&item->bounds, &max_rect, &max_rect);
  184.             usb.integer = 0;
  185.             usb.bytes[1] = item->data[0];
  186.      
  187.             switch ( item->type & 0x7F )
  188.             {
  189.                 case ctrlItem + btnCtrl :
  190.                 case ctrlItem + chkCtrl :
  191.                 case ctrlItem + radCtrl :
  192.                     item->handle = (Handle)NewControl((DialogPtr) dialog,
  193.                         &item->bounds, (StringPtr)item->data, true,
  194.                         0, 0, 1, item->type & 0x03, 0);
  195.                 break;
  196.      
  197.                 case ctrlItem + resCtrl :
  198.                 {
  199.                     item->handle = (Handle)GetNewControl(*(short*)(item->data + 1), (DialogPtr) dialog);
  200.                     (**(ControlHandle)item->handle).contrlRect = item->bounds;
  201.                 }
  202.                 break;
  203.     
  204.                 case statText :
  205.                 case editText :
  206.                     err = PtrToHand(item->data + 1, &item->handle, usb.integer);
  207.                 break;
  208.     
  209.                 case iconItem :
  210.                     item->handle = GetIcon(*(short*)(item->data + 1));
  211.                 break;
  212.      
  213.                 case picItem :
  214.                     item->handle = (Handle)GetPicture(*(short*)(item->data + 1));
  215.                 break;
  216.      
  217.                 default :
  218.                     item->handle = NULL;
  219.             }
  220.      
  221.             data_size = (usb.integer + 1) & 0xFFFE;
  222.             item = (DialogItemPtr)((char*)item + data_size + sizeof(DialogItem));
  223.         }
  224.      
  225.      /* We need to subtract the short below because otherwise the size of the DITL count
  226.      ** gets factored in twice, and the resulting DTIL has two bytes of garbage appended
  227.      ** to it. This is a problem with the original TN#95 code as well.
  228.      */
  229.      
  230.         err = PtrAndHand((**append_item_list).items,
  231.                         (Handle)dlg_item_list,
  232.                         GetHandleSize((Handle) append_item_list)
  233.                         - sizeof(short));
  234.     
  235.         (**dlg_item_list).max_index += new_items;
  236.         HUnlock((Handle) append_item_list);
  237.         ReleaseResource((Handle) append_item_list);
  238.      
  239.         max_rect.bottom += 5;
  240.         max_rect.right += 5;
  241.         SizeWindow((WindowPtr) dialog, max_rect.right, max_rect.bottom, true);
  242.      
  243.         return first_item;
  244.     }
  245. }
  246.  
  247.  
  248. /*------------------------------------------------------------------------*/
  249.  
  250. OSErr Print(void)
  251. {
  252.     TPPrPort    pPrPort;
  253.     Rect        aRect;
  254.     TPrStatus    theStatus;
  255.  
  256.  
  257.     /* call PrJobInit to get pointer to the invisible job dialog */
  258.     hPrintRec = (THPrint)(NewHandle(sizeof(TPrint)));
  259.     PrintDefault(hPrintRec);
  260.     PrValidate(hPrintRec);
  261.     if (PrError() != noErr)
  262.         return PrError();
  263.  
  264.     PrtJobDialog = PrJobInit(hPrintRec);
  265.  
  266.     if (PrError() != noErr)
  267.         return PrError();
  268.  
  269.     if (!PrDlgMain(hPrintRec, NewPDlgInitProc(MyJobDlgInit))) /* this line does all the stuff */
  270.         return iPrAbort;
  271.  
  272.     if (PrError() != noErr)
  273.         return PrError();
  274.  
  275.     pPrPort = PrOpenDoc(hPrintRec, NULL, NULL);
  276.     PrOpenPage(pPrPort, NULL);
  277.  
  278.     aRect = (*hPrintRec)->prInfo.rPage;
  279.     InsetRect(&aRect, 20, 20);
  280.     PenSize(4, 4);
  281.     FrameRect(&aRect);
  282.  
  283.     PrClosePage(pPrPort);
  284.     PrCloseDoc(pPrPort);
  285.  
  286.     if (!PrError() && (*hPrintRec)->prJob.bJDocLoop == bSpoolLoop)
  287.         PrPicFile(hPrintRec, NULL, NULL, NULL, &theStatus);
  288.  
  289.  
  290. /* that's all for now */
  291.  
  292.     if (hPrintRec) DisposeHandle((Handle) hPrintRec);
  293.  
  294.     return(noErr);
  295. } /* Print */
  296.  
  297. /*------------------------------------------------------------------------*/
  298.  
  299. pascal TPPrDlg MyJobDlgInit(THPrint hPrint)
  300. /*
  301.     this routine appends items to the standard job dialog and sets up the
  302.     user fields of the printing dialog record TPRDlg
  303.  
  304.     This routine will be called by PrDlgMain
  305. */
  306.  
  307. {
  308. #pragma unused(hPrint)
  309.  
  310.     short    firstItem;    /* first new item number */
  311.  
  312.     short    itemType, item;
  313.     Handle    itemH;
  314.     Rect    itemBox;
  315.  
  316.     firstItem = Append_DITL(PrtJobDialog, MyDITL); /*call routine to do this */
  317.  
  318.     prFirstItem = firstItem; /* save this so MyJobItems can find it */
  319.  
  320. /* now we'll set up our DITL items -- The radio buttons */
  321.  
  322.     for (item = 5; item <= 7; item++)
  323.     {
  324.         GetDItem((DialogPtr) PrtJobDialog,firstItem + item -1,&itemType,&itemH,&itemBox);
  325.         SetCtlValue((ControlHandle) itemH, (item == 5));
  326.     }
  327.  
  328. /* now we'll set up the second of our DITL items -- The checkbox */
  329.  
  330.     GetDItem((DialogPtr) PrtJobDialog,firstItem +2,&itemType,&itemH,&itemBox);
  331.     SetCtlValue((ControlHandle) itemH,1);
  332.  
  333. /*
  334.     Now comes the part where we patch in our item handler. We have to save
  335.     the old item handler address, so we can call it if one of the standard
  336.     items is hit, and put our item handler's address in pItemProc field of
  337.     the TPrDlg struct
  338. */
  339.  
  340.     prPItemProc = PrtJobDialog->pItemProc;
  341.  
  342. /* Now we'll tell the modal item handler where our routine is */
  343.     PrtJobDialog->pItemProc = NewPItemProc(MyJobItems) ;
  344.  
  345.  
  346. /* PrDlgMain expects a pointer to the modified dialog to be returned...*/
  347.     return PrtJobDialog;
  348.  
  349. } /*myJobDlgInit*/
  350.  
  351. /*-----------------------------------------------------------------------*/
  352.  
  353. static pascal Boolean    testFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
  354. {
  355. #pragma unused(theDialog)
  356. #pragma unused(theEvent)
  357. #pragma unused(itemHit)
  358. //    DebugStr("\pMy filter proc got called");    // This gets called a lot if you uncomment it
  359.     return false;
  360. }
  361.  
  362. static pascal void testDialogUserItem(WindowPtr theWindow, short itemNo);
  363. static pascal void testDialogUserItem(WindowPtr theWindow, short itemNo)
  364. {
  365.     if (itemNo != 4) return;
  366.     else {
  367.         short    oldFont = ((GrafPtr)theWindow)->txFont;
  368.         short    oldSize = ((GrafPtr)theWindow)->txSize;
  369.         short    itemType;
  370.         Handle    h;
  371.         Rect    r;
  372.  
  373.         SetPort(theWindow);
  374.         TextFont(GetAppFont());
  375.         TextSize(9);
  376.         GetDialogItem((DialogPtr)theWindow,4,&itemType,&h,&r);
  377.         MoveTo(r.left,r.bottom);
  378.         DrawString("\p<http://www.winternet.com/~dask/poohsnif.html>");
  379.         TextFont(oldFont);
  380.         TextSize(oldSize);
  381.     }
  382. }
  383.  
  384. static void TestDialog(void);
  385. static void TestDialog(void)
  386. {
  387.     DialogPtr    theDialog = GetNewDialog(257,nil,(WindowPtr)-1L);
  388.     short    itemHit = 0;
  389.     ModalFilterUPP    mySubDialogFilterProc = nil;    // NewModalFilterProc(testFilter); // for testing
  390.     UserItemUPP        mySubDialogUserProc = NewUserItemProc(testDialogUserItem);
  391.  
  392.     {        // set up the user item
  393.         short    t;
  394.         Handle    h;
  395.         Rect    r;
  396.         
  397.         GetDialogItem(theDialog,4,&t,&h,&r);
  398.         SetDialogItem(theDialog,4,t,(Handle)mySubDialogUserProc,&r);
  399.     }
  400.  
  401.     SetDialogDefaultItem(theDialog,1);
  402.     while(itemHit != 1) {    // a WAY bad way of seeing if we're done, but I'm in a hurry
  403.         ModalDialog(mySubDialogFilterProc, &itemHit);
  404.     }
  405.     DisposeDialog(theDialog);
  406.     if (mySubDialogFilterProc != nil)
  407.         DisposeRoutineDescriptor(mySubDialogFilterProc);
  408.     if (mySubDialogUserProc != nil)
  409.         DisposeRoutineDescriptor(mySubDialogUserProc);
  410. }
  411.  
  412. /* here's the analogue to the SF dialog hook */
  413.  
  414. pascal void MyJobItems( TPPrDlg theDialog, short itemNo )
  415. { /* MyJobItems */
  416.     short    myItem;
  417.     short    firstItem, item, itemType, theValue;
  418.     Handle    itemH;
  419.     Rect    itemBox;
  420.  
  421.     firstItem = prFirstItem;    /* remember, we saved this in myJobDlgInit */
  422. //    DebugStr("\p Looking at the item...");
  423.     myItem = itemNo-firstItem+1;    /* "localize" current item No */
  424.     if (myItem > 0)    /* if localized item > 0, it's one of ours */
  425.     {
  426.         /* find out which of our items was hit */
  427.  
  428.         switch (myItem)
  429.         {
  430.             case 1:            /*    Static text.    */
  431.                 break;
  432.             case 2:            /*    Edit text.        */
  433.                 break;
  434.             case 3:            /*    Check box.        */
  435.                     GetDItem((DialogPtr) theDialog,firstItem +2,&itemType,&itemH,&itemBox);
  436.                      theValue = GetCtlValue((ControlHandle) itemH);
  437.                      SetCtlValue((ControlHandle) itemH, theValue != 1);
  438.                 break;
  439.             case 4:            /*    Push button.    */
  440.                 TestDialog();
  441.                 break;
  442.             case 5:            /*    Radio buttons    */
  443.             case 6:
  444.             case 7:
  445.                 for (item = 5; item <= 7; item++) {
  446.                     GetDItem((DialogPtr) theDialog,firstItem +item -1,&itemType,&itemH,&itemBox);
  447.                      SetCtlValue((ControlHandle) itemH, item == myItem);
  448.                 }
  449.                 break;
  450.             case 8:            /*    Edit text.        */
  451.                 break;
  452.             default: Debugger(); /* OH OH */
  453.         } /* switch */
  454.     } /* if (myItem > 0) */
  455.     else /* chain to standard item handler, whose address is saved in prPItemProc */
  456.     {
  457.         CallPItemProc(prPItemProc,(DialogPtr)theDialog, itemNo);
  458.     }
  459. } /* MyJobItems */
  460.  
  461.  
  462. void main(void)
  463. {
  464.     Rect    myWRect;
  465.  
  466.     InitGraf(&qd.thePort);
  467.     InitFonts();
  468.     InitWindows();
  469.     InitMenus();
  470.     InitDialogs((long)nil);
  471.     InitCursor();
  472.     SetRect(&myWRect,50,260,350,340);
  473.  
  474.     /* call the routine that does printing */
  475.     PrOpen();
  476.     err = Print();
  477.  
  478.     PrClose();
  479. } /* main */
  480.